package command;

import common.ParseException;
import file.FileString;

import java.util.ArrayList;

public abstract class Cmd {
    private FileString parentFileString;
    private ArrayList<Cmd> body;

    protected Cmd(FileString parentFileString) {
        this.parentFileString = parentFileString;
        body = new ArrayList<Cmd>();
    }

    public FileString getParentFileString() {
        return parentFileString;
    }

    public ArrayList<Cmd> getBody() {
        return body;
    }

    public void addCmdToBody(Cmd cmd) {
        addCmdToBody(cmd.parentFileString.getSpaceShift(), cmd);
    }

    public void addCmdToBody(int shift, Cmd cmd) {
        cmd.getParentFileString().setSpaceShift(shift);
        if (body.size() == 0 || shift <= body.get(body.size() - 1).getParentFileString().getSpaceShift())
            body.add(cmd);
        else
            body.get(body.size() - 1).addCmdToBody(shift, cmd);
    }

    public static Cmd getCommand(FileString string) throws ParseException {
        if (string.getCommand().length() == 0 && string.getComment().length() == 0)
            return new Empty(string);
        else if (string.getCommand().length() == 0)
            return new Comment(string);
        else if (string.getCommand().startsWith("@@"))
            return new Anchor(string);
        else if (
                string.getCommand().startsWith("&") ||
                        string.getCommand().indexOf(':') < 0 ||
                        string.getCommand().indexOf(':') >= 0 && doubleDotSameWithPseudoClass(string.getCommand()))
            return new Selector(string);
        else if (string.getCommand().startsWith("@include"))
            return new Include(string);
        else if (string.getCommand().startsWith("@"))
            return new Var(string);
        else if (string.getTrimmedOriginalString().startsWith("~~{") && string.getTrimmedOriginalString().endsWith("}"))
            return new StaticText(string);
        else if (string.getTrimmedOriginalString().startsWith("~{") && string.getTrimmedOriginalString().endsWith("}"))
            return new DynamicText(string);
        else if (string.getCommand().indexOf(':') > 0)
            return new Command(string);
        throw new ParseException(string, "Нет соответствия этой строки любому из типов элемента");
    }

    static boolean doubleDotSameWithPseudoClass(String text) {
        String[] psevdoClasses = {
                ":-moz-placeholder",
                ":active",
                ":after",
                ":before",
                ":checked",
                ":default",
                ":disabled",
                ":empty",
                ":enabled",
                ":first-child",
                ":first-letter",
                ":first-line",
                ":first-of-type",
                ":focus",
                ":hover",
                ":indeterminate",
                ":invalid",
                ":lang",
                ":last-child",
                ":last-of-type",
                ":link",
                ":not",
                ":nth-child",
                ":nth-last-child",
                ":nth-last-of-type",
                ":nth-of-type",
                ":only-child",
                ":only-of-type",
                ":optional",
                ":read-only",
                ":read-write",
                ":required",
                ":root",
                ":target",
                ":valid",
                ":visited",
                "::-moz-selection",
                "::after",
                "::before",
                "::first-letter",
                "::first-line",
                "::selection"
        }; // String[] psevdoClasses
        int i = text.indexOf(':');
        for (String str : psevdoClasses)
            if (i == text.indexOf(str))
                return true;
        return false;
    }

    @Override
    public String toString() {
        return parentFileString.getCommand() + ((parentFileString.getComment().length() > 0) ? "//" + parentFileString
                .getComment() : "") ;
    }

    public abstract Cmd getCopy() throws ParseException;
}
